
                /*********************************************
                **                                          **
                **                                          **
                **                 gatherv-r                **
                **                                          **
                **                                          **
                *********************************************/
                /*********************************************
                **                                          **
                **         Author Jean-Marc Adamo           **
                **       Copyright (C) 1997-2008 JMA        **
                *********************************************/


/*
** execute with 6 processes
*/

#include "arch.h"
#include "A.utilities"

//user program

Coll_id cid1, cid2, cid3, cid_bar, cid_gather1, cid_gather2;

//on most homogenous systems, explicit setting 
//wont be necessary (try commenting the
//setting lines, you should get the same values
//for the cids).
void init(int, char **){
   cid1.set();
   cid2.set();
   cid3.set();
   cid_bar.set();
   cid_gather1.set();
   cid_gather2.set();
   fprintf(Sdf::trace, "node%d: cid1=%d, cid2=%d, cid3=%d, cid_bar=%d, cid_gather1=%d,cid_gather2=%d\n",
           Sdf::PROC_ID, 
           cid1.get(), cid2.get(), cid3.get(),
           cid_bar.get(), cid_gather1.get(), cid_gather2.get());
   fflush(Sdf::trace);
}

class Proc: public S_Thread{

   public:
        int pid;
        int step;

        Proc(int p, int s)
                : S_Thread((Smf0_ptr)&Proc::body){pid = p; step = s;}

        void body(){
               fprintf(Sdf::trace, "node %d, in proc %d before loop at step %d, this_thread=%d\n",
                       Sdf::PROC_ID, pid, step, Sdf::this_thread);
               fflush(Sdf::trace);
               int i;
               for(i = 0; i < 4; i++){
                   reschedule();
               }
  
               if(step<1){

                   int *from;

                   int to[33];
                   for(i=0; i<33; i++){
                      to[i] = 777;
                   }

                   int rcounts[6] = {1, 2, 3, 4, 5, 6};
                   int rdispls[6] = {0, 1, 4, 9, 16, 25};

                   if(pid == 1){
                      from = new int[Sdf::PROC_ID+1];
                      for(i=0; i<Sdf::PROC_ID+1; i++){
                         from[i] = Sdf::PROC_ID;
                      }

                      fprintf(Sdf::trace, "node %d, in proc %d ***before gather at step %d\n",
                              Sdf::PROC_ID, pid, step);
                      fflush(Sdf::trace);

                        //each process supplies Sdf::PROC_ID+1 integers.
                        //All integers are gathered in one process.according
                        //to rcounts and rdispls.
                      _Sdf<int>::gather(from[0], to[0], rcounts, rdispls, 4, cid_gather1);

                      Sdf::barrier(cid_bar);

                   }else{

                      Group *group1;
                      int rk1[3];
                      for(i = 0; i < 3; i++)
                         rk1[i] = i;
                      group1 = Sdf::incl(Sdf::COMML_WORLD, 3, rk1);
                      CommL *comm1 = group1->commit(cid1, Sdf::COMML_WORLD);

                      Group *group2;
                      int rk2[3];
                      for(i = 3; i < Sdf::PROC_NB; i++)
                         rk2[i-3] = i;
                      group2 = Sdf::incl(Sdf::COMML_WORLD, Sdf::PROC_NB-3, rk2);
                      CommL *comm2 = group2->commit(cid2, Sdf::COMML_WORLD);

                      Sdf::barrier(cid_bar);

                      CommR *commr;
                      commr = Sdf::newCommR(cid3, comm1, comm2, Sdf::COMML_WORLD);

                      fprintf(Sdf::trace, "node %d, in proc %d ***before gather at step %d\n",
                              Sdf::PROC_ID, pid, step);
                      fflush(Sdf::trace);

                        //All processes in comm2 and the root process
                        //in comm1 supply integers that are gathered
                        //in the root process.according to rcounts and rdispls.
                      if(Sdf::PROC_ID < 3){
                        if(commr->get_local_CommL()->rank() == 1){
                           int f = Sdf::PROC_ID;
                           from = &f;
                           _Sdf<int>::gather(from[0], to[0], rcounts, rdispls, Sdf::ROOT, cid_gather2, commr);
                        }else{
                           int dummy;
                           _Sdf<int>::gather(dummy, to[0], rcounts, rdispls, Sdf::NOPID, cid_gather2, commr);
                        }
                      }else{
                           from = new int[Sdf::PROC_ID-1];
                           for(i=0; i<Sdf::PROC_ID-1; i++){
                              from[i] = Sdf::PROC_ID;
                           }
                           _Sdf<int>::gather(from[0], to[0], rcounts, rdispls, 1, cid_gather2, commr);
                      }

                      delete comm1;
                      delete comm2;
                      delete commr;
                   }

                   fprintf(Sdf::trace, "node %d, in proc %d ***after t_gather, to=%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
                           Sdf::PROC_ID, pid, 
                           to[0], to[1], to[2], to[3], to[4], to[5], to[6], to[7],
                           to[8], to[9], to[10], to[11], to[12], to[13], to[14], to[15],
                           to[16], to[17], to[18], to[19], to[20], to[21], to[22], to[23],
                           to[24], to[25], to[26], to[27], to[28], to[29], to[30], to[31], to[32]);
                   fflush(Sdf::trace);

                   if(pid==1 || (pid==2 && Sdf::PROC_ID >= 3))
                      delete []from;

                   Proc *proc1 = new Proc(pid*10 + 1, step+1);
                   Proc *proc2 = new Proc(pid*10 + 2, step+1);
                   S_Thread *proc_tabl[2] = {proc1, proc2};
                   int pri[2] = {1, 1};
                   par(2, proc_tabl, pri);
                   delete proc1;
                   delete proc2;
               }
               fprintf(Sdf::trace, "on node %d, proc %d the end at step %d\n",
                        Sdf::PROC_ID, pid, step);
               fflush(Sdf::trace);
        }
};

class Root_proc: public Thread{

   public:

        Root_proc()
                : Thread((Tmf0_ptr)&Root_proc::body){}

        void body(){

                fprintf(Sdf::trace, "node %d, in Root_proc::body1, this_thread=%d\n", 
				        Sdf::PROC_ID, Sdf::this_thread);
                fflush(Sdf::trace);
                Proc *proc1 = new Proc(1, 0);
                Proc *proc2 = new Proc(2, 0);
                fprintf(Sdf::trace, "node %d, in Root_proc::body2\n", Sdf::PROC_ID);
                fflush(Sdf::trace);
                S_Thread *proc_tabl[2] = {proc1, proc2};
                int pri[2] = {1, 1};
                par(2, proc_tabl, pri);
                fprintf(Sdf::trace, "node %d, in Root_proc::body4\n", Sdf::PROC_ID);
                fflush(Sdf::trace);
                delete proc1;
                delete proc2;
        }
};
//end of user program

MAIN(Root_proc, init, Sdf::empty, Sdf::empty)

